// +FHDR----------------------------------------------------------
// Copyright (c) 2023, RJMicro Technology Co.,Ltd.
// RJMicro Confidential Proprietary
// ---------------------------------------------------------------
// FILE NAME       : .v
// DEPARTMENT      : IC Dept
// AUTHOR          :
// AUTHOR'S EMAIL  :
// ---------------------------------------------------------------
//
// Description     :
// 12'h000  CR
// 12'h004  SR0
// 12'h008  SR1
// 12'h00C  CMD
// 12'h010  CMD_EXE
// 12'h01C  BYTES
// 12'h020  ADDR
// 12'h024  DATA0
// 12'h028  DATA1
// 12'h02C  DATA2
// 12'h034  INIT
// 12'h038  IER
// 12'h03C  CLR
// 12'h040  PARAM0
// 12'h044  PARAM1
// 12'h060  TRIM0
// 12'h064  TRIM1
// 12'h068  TRIM2
// 12'h06C  FTST
// 12'h070  TRIM_KEY
// 12'h074  PARAM_KEY
// 12'h080  ECC_INL
// 12'h084  ECC_INM
// 12'h088  ECC_INH
// -FHDR
// ---------------------------------------------------------------

module fmc_regfile (
    output [02:0]          cr_prescaler_cfg    ,
    output                 cr_dpstb_en         ,
    output                 cr_preadyen         ,
    output                 cr_filter_ff        ,
    input                  sr0_star_err        ,
    input  [01:0]          sr0_ecc_err         ,
    input  [07:0]          sr0_ecc_synd        ,
    input  [31:0]          sr1_ecc_err_addr    ,
    output                 cmd_exe_exe         ,
    output [07:0]          bytes_prog_bytes    ,
    output [31:0]          addr                ,
    output [31:0]          data0               ,
    output [31:0]          data1               ,
    output [07:0]          data2               ,
    output                 ftst_readm0         ,
    output                 ftst_readm1         ,
    output [15:0]          ftst_tst_key        ,
    output [31:0]          param_key           ,
    input                  hclk                ,
    input                  hrstn               ,

    input                  hready              ,
    input  [31:0]          haddr               ,
    input                  hwrite              ,
    input  [01:0]          htrans              ,
    input  [02:0]          hsize               ,
    input  [31:0]          hwdataa              ,

//   output                 hreadyout           ,
//   output                 hreadyout_peri      ,
    input                   hsel_fmc            ,
    output [31:0]           hrdata_fmc
);

// ------------------------------------------------------------
// AHB write read enable
// ------------------------------------------------------------
wire            ahb_cs    = hsel_fmc & hready & htrans[1];
wire            read_en   = ahb_cs & (~hwrite);
reg     [11:2]  addr;
reg             write_en;
reg     [31:0]  ff_rdata;

always @(posedge hclk or negedge hrstn) begin
    if (~hrstn) begin
        addr      <= 6'h0;
        write_en  <= 1'h0;
    end else begin
        addr      <= haddr[11:2];
        write_en  <= ahb_cs & (~hwrite);
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        hrdata_fmc <= 32'b0;
    else if (read_en) 
        hrdata_fmc <= ff_rdata[31:0];
end

// ------------------------------------------------------------
// Internal Signals
// ------------------------------------------------------------
reg     [02:0]  ff_cr_prescaler_cfg ;
reg             ff_cr_dpstb_en      ;
reg             ff_cr_preadyen      ;
reg             ff_cr_filter_ff     ;
reg             ff_cmd_exe_exe      ;
reg     [07:0]  ff_bytes_prog_bytes ;
reg     [31:0]  ff_addr             ;
reg     [31:0]  ff_data0            ;
reg     [31:0]  ff_data1            ;
reg     [07:0]  ff_data2            ;
reg             ff_ftst_readm0      ;
reg             ff_ftst_readm1      ;
reg     [15:0]  ff_ftst_tst_key     ;
reg     [31:0]  ff_param_key        ;

wire            wir_sr0_star_err    ;
wire    [01:0]  wir_sr0_ecc_err     ;
wire    [07:0]  wir_sr0_ecc_synd    ;
wire    [31:0]  wir_sr1_ecc_err_addr;
assign          wir_sr0_star_err    = sr0_star_err        ;
assign          wir_sr0_ecc_err     = sr0_ecc_err[01:0]   ;
assign          wir_sr0_ecc_synd    = sr0_ecc_synd[07:0]  ;
assign          wir_sr1_ecc_err_addr= sr1_ecc_err_addr[31:0];

// ------------------------------------------------------------
// write_process
// ------------------------------------------------------------
wire     wren_cr             = write_en & (addr[11:2] == 10'h0);
wire     wren_cmd_exe        = write_en & (addr[11:2] == 10'h4);
wire     wren_bytes          = write_en & (addr[11:2] == 10'h7);
wire     wren_addr           = write_en & (addr[11:2] == 10'h8);
wire     wren_data0          = write_en & (addr[11:2] == 10'h9);
wire     wren_data1          = write_en & (addr[11:2] == 10'ha);
wire     wren_data2          = write_en & (addr[11:2] == 10'hb);
wire     wren_ftst           = write_en & (addr[11:2] == 10'h1b);
wire     wren_param_key      = write_en & (addr[11:2] == 10'h1d);

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_cr_prescaler_cfg <= 3'h0;
    else if (wren_cr) begin
        ff_cr_prescaler_cfg <= wdata[2:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_cr_dpstb_en <= 1'h0;
    else if (wren_cr) begin
        ff_cr_dpstb_en <= wdata[24];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_cr_preadyen <= 1'h0;
    else if (wren_cr) begin
        ff_cr_preadyen <= wdata[25];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_cr_filter_ff <= 1'h0;
    else if (wren_cr) begin
        ff_cr_filter_ff <= wdata[27];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_cmd_exe_exe <= 1'h0;
    else if (wren_cmd_exe) begin
        ff_cmd_exe_exe <= wdata[31];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_bytes_prog_bytes <= 8'h0;
    else if (wren_bytes) begin
        ff_bytes_prog_bytes <= wdata[7:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_addr <= 32'h0;
    else if (wren_addr) begin
        ff_addr <= wdata[31:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_data0 <= 32'h0;
    else if (wren_data0) begin
        ff_data0 <= wdata[31:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_data1 <= 32'h0;
    else if (wren_data1) begin
        ff_data1 <= wdata[31:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_data2 <= 8'h0;
    else if (wren_data2) begin
        ff_data2 <= wdata[7:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_ftst_readm0 <= 1'h0;
    else if (wren_ftst) begin
        ff_ftst_readm0 <= wdata[0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_ftst_readm1 <= 1'h0;
    else if (wren_ftst) begin
        ff_ftst_readm1 <= wdata[1];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_ftst_tst_key <= 16'h0;
    else if (wren_ftst)
        ff_ftst_tst_key <= wdata[31:16];
    else 
        ff_ftst_tst_key <= 16'h0;
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_param_key <= 32'h0;
    else if (wren_param_key)
        ff_param_key <= wdata[31:0];
    else 
        ff_param_key <= 32'h0;
end


// ------------------------------------------------------------
// read_process
// ------------------------------------------------------------

wire  [31:0]  wir_r_cr       = {4'h0, ff_cr_filter_ff, 1'h0, ff_cr_preadyen, ff_cr_dpstb_en, 21'h0, ff_cr_prescaler_cfg[2:0]};
wire  [31:0]  wir_r_sr0      = {16'h0, wir_sr0_ecc_synd[15:8], 2'h0, wir_sr0_ecc_err[5:4], 3'h0, wir_sr0_star_err};
wire  [31:0]  wir_r_sr1      = {wir_sr1_ecc_err_addr[31:0]};
wire  [31:0]  wir_r_cmd_exe  = {ff_cmd_exe_exe, 31'h0};
wire  [31:0]  wir_r_bytes    = {24'h0, ff_bytes_prog_bytes[7:0]};
wire  [31:0]  wir_r_addr     = {ff_addr[31:0]};
wire  [31:0]  wir_r_data0    = {ff_data0[31:0]};
wire  [31:0]  wir_r_data1    = {ff_data1[31:0]};
wire  [31:0]  wir_r_data2    = {24'h0, ff_data2[7:0]};
wire  [31:0]  wir_r_ftst     = {30'h0, ff_ftst_readm1, ff_ftst_readm0};

always @ (*) begin
    ff_rdata = 32'h0;
    if (read_en) begin
        case (addr[11:2])
            10'b0000000000     :    ff_rdata = wir_r_cr;
            10'b0000000001     :    ff_rdata = wir_r_sr0;
            10'b0000000010     :    ff_rdata = wir_r_sr1;
            10'b0000000100     :    ff_rdata = wir_r_cmd_exe;
            10'b0000000111     :    ff_rdata = wir_r_bytes;
            10'b0000001000     :    ff_rdata = wir_r_addr;
            10'b0000001001     :    ff_rdata = wir_r_data0;
            10'b0000001010     :    ff_rdata = wir_r_data1;
            10'b0000001011     :    ff_rdata = wir_r_data2;
            10'b0000011011     :    ff_rdata = wir_r_ftst;
            default: ff_rdata = 32'h0;
        endcase
    end
end
// ------------------------------------------------------------
// Assign
// ------------------------------------------------------------
assign  cr_prescaler_cfg    = ff_cr_prescaler_cfg ;
assign  cr_dpstb_en         = ff_cr_dpstb_en      ;
assign  cr_preadyen         = ff_cr_preadyen      ;
assign  cr_filter_ff        = ff_cr_filter_ff     ;
assign  cmd_exe_exe         = ff_cmd_exe_exe      ;
assign  bytes_prog_bytes    = ff_bytes_prog_bytes ;
assign  addr                = ff_addr             ;
assign  data0               = ff_data0            ;
assign  data1               = ff_data1            ;
assign  data2               = ff_data2            ;
assign  ftst_readm0         = ff_ftst_readm0      ;
assign  ftst_readm1         = ff_ftst_readm1      ;
assign  ftst_tst_key        = ff_ftst_tst_key     ;
assign  param_key           = ff_param_key        ;
// ------------------------------------------------------------
// End of the module
// ------------------------------------------------------------
endmodule
